package com.aya.tb;

import com.aya.tb.context.StandardParameterResolver;
import com.aya.tb.annotation.RequestMapping;
import com.aya.tb.context.ArgumentSupportHandler;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.MethodIntrospector;
import org.springframework.stereotype.Service;
import org.springframework.util.ReflectionUtils;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;

@Service
public class TreeBridgeListener implements ApplicationListener<ContextRefreshedEvent> {

    @Resource
    MappingProxy mappingProxy;

    @Resource
    StandardParameterResolver standardParameterResolver;

    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
        initMappingProxy(contextRefreshedEvent.getApplicationContext(), mappingProxy);
        initArgymentHandler(contextRefreshedEvent.getApplicationContext(),standardParameterResolver);
    }

    private void initArgymentHandler(ApplicationContext applicationContext, StandardParameterResolver standardParameterResolver) {
        Map<String, ArgumentSupportHandler> beansOfType = applicationContext.getBeansOfType(ArgumentSupportHandler.class);
        for (ArgumentSupportHandler value : beansOfType.values()) {
            standardParameterResolver.addArgumentHandler(value);
        }

    }

    private void initMappingProxy(ApplicationContext applicationContext, MappingProxy mappingProxy) {
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            Class<?> type = applicationContext.getType(beanDefinitionName);

            Set<Method> methods = MethodIntrospector.selectMethods(type, new ReflectionUtils.MethodFilter() {
                @Override
                public boolean matches(Method method) {
                    return method.isAnnotationPresent(RequestMapping.class);
                }
            });

            for (Method method : methods) {
                RequestMapping annotation = method.getAnnotation(RequestMapping.class);
                RequestMap requestMap = new RequestMap(method, applicationContext.getBean(beanDefinitionName),method.getParameters());
                mappingProxy.putRequestMap(annotation.code(), requestMap);
            }
        }
    }
}
